package com.ssy.jt808.gateway.application.endpoint;

import com.ssy.jt808.gateway.adapter.model.APICodes;
import com.ssy.jt808.gateway.adapter.model.APIResult;
import com.ssy.jt808.gateway.domain.exception.TerminalStatusException;
import com.ssy.jt808.protocol.basics.JTMessage;
import com.ssy.netmc.session.Session;
import com.ssy.netmc.session.SessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.time.Duration;

/**
 * @author yezhihao
 */
@Component
public class MessageManager{

    private static final Logger     log               = LoggerFactory.getLogger(MessageManager.class);
    private static final Mono<Void> NEVER             = Mono.never();
    private static final Mono       OFFLINE_EXCEPTION = Mono.error(new TerminalStatusException(
      String.valueOf(APICodes.OfflineClient.getCode()),
      "设备已离线"));
    private static final Mono
                                    OFFLINE_RESULT
                                                      =
      Mono.just(new APIResult<>(APICodes.OfflineClient,
                                                                                  "设备已离线"));
    private static final Mono
                                    SENDFAIL_RESULT
                                                      =
      Mono.just(new APIResult<>(APICodes.BadRequest,
                                                                                  "消息发送失败"));
    private static final Mono       TIMEOUT_RESULT    = Mono.just(new APIResult<>(APICodes.Timeout,
                                                                                  "消息发送成功,设备响应超时"));

    private SessionManager sessionManager;

    public MessageManager( SessionManager sessionManager ){
        this.sessionManager = sessionManager;
    }

    public Mono<Void> notifyR( String sessionId, JTMessage request ){
        Session session = sessionManager.get(sessionId);
        if( session == null ){
            return OFFLINE_EXCEPTION;
        }

        return session.notify(request);
    }

    public Mono<Void> notify(String sessionId, JTMessage request) {
        Session session = sessionManager.get(sessionId);
        if (session == null){
            return NEVER;
        }

        return session.notify(request);
    }

    public <T> Mono<APIResult<T>> requestR(String sessionId, JTMessage request, Class<T> responseClass) {
        Session session = sessionManager.get(sessionId);
        if (session == null){
            return OFFLINE_RESULT;
        }

        return session.request(request, responseClass)
                      .map(message->APIResult.ok(message))
                      .timeout(Duration.ofSeconds(15), TIMEOUT_RESULT)
                      .onErrorResume(e -> {
                    log.warn("消息发送失败", e);
                    return SENDFAIL_RESULT;
                });
    }

    @SuppressWarnings("all")
    public <T> Mono<APIResult<T>> requestR(JTMessage request, Class<T> responseClass) {
        Session session = sessionManager.get(request.getClientId());
        if (session == null){
            return OFFLINE_RESULT;
        }

        return session.request(request, responseClass)
                      .map(message->APIResult.ok(message))
                      .timeout(Duration.ofSeconds(15), TIMEOUT_RESULT)
                      .onErrorResume(e->{
                          log.warn("消息发送失败", e);
                          return SENDFAIL_RESULT;
                      });
    }


    @SuppressWarnings("all")
    public <T> Mono<APIResult<T>> requestR( JTMessage request,
                                            Class<T> responseClass,
                                            int timeout ){
        Session session = sessionManager.get(request.getClientId());
        if( session == null ){
            return OFFLINE_RESULT;
        }

        return session.request(request, responseClass)
                      .map(message->APIResult.ok(message))
                      .timeout(Duration.ofSeconds(timeout), TIMEOUT_RESULT)
                      .onErrorResume(e->{
                          log.warn("消息发送失败", e);
                          return SENDFAIL_RESULT;
                      });
    }

    public <T> Mono<T> request( String sessionId,
                                JTMessage request,
                                Class<T> responseClass,
                                long timeout ){
        return request(sessionId, request, responseClass).timeout(Duration.ofMillis(timeout));
    }

    public <T> Mono<T> request( String sessionId, JTMessage request, Class<T> responseClass ){
        Session session = sessionManager.get(sessionId);
        if( session == null ){
            return OFFLINE_EXCEPTION;
        }

        return session.request(request, responseClass);
    }
}